function [decisions, dvals, nbc] = decide_from_labelednbs(scores, rlabels, K, filter, fevl, preHigh, postHigh)
%DECIDE_FROM_LABELEDNBS Decides labels from labeled neighbors
%
% [ Syntax ]
%   - [decisions, dvals] = decide_from_labelednbs(scores, rlabels, K, 
%                                                 filter, fevl, preHigh, postHigh)
%
% [ Arguments ]
%   - scores:       the whole score matrix (nr x n)
%   - rlabels:      the labels of the referenced samples
%   - K:            the maximum neighborhood size
%   - filter:       the score filtering function handle
%   - fevl:         the score summarize function handle
%   - preHigh:      whether higher score indicates better match
%   - postHigh:     whether higher decision value indicates better match
%
% [ History ]
%   - Created by Dahua Lin, on Jul 18, 2007
%

% get size information
[nr, n] = size(scores);

% sort the scores and take the K best matches
if preHigh
    [ss, si] = sort(scores, 1, 'descend');
else
    [ss, si] = sort(scores, 1, 'ascend');
end
ss = ss(1:K, :);
si = si(1:K, :);

if ~isempty(filter)       
    is_valid = filter(ss);
end

% construct edge set of the neighbor-class graph
rlabels = rlabels(:);
[rlabelset, dummy, rlabelinds] = unique(rlabels);

sc = reshape(rlabelinds(si), size(si));
E = sub2ind([length(rlabelset) n], sc, repmat(1:n, [K 1]));

if isempty(filter)
    E = E(:);
    V = ss(:);
else
    E = E(is_valid);
    V = ss(is_valid);
end

% reduce the graph and make summary
[Eset, grps, Emap] = unique_map(E);

Evs = cellfun(@(x) fevl(V(x)), grps);

% fill back the summarized values
if isempty(filter)
    M = reshape(Evs(Emap), [K, n]);
else
    M = nan(K, n);
    M(is_valid) = Evs(Emap);
end

% make decisions

if postHigh
    [dvals, decisions] = max(M, [], 1);
else
    [dvals, decisions] = min(M, [], 1);
end
decisions = rlabelset(sc(sub2ind(size(sc), decisions, 1:n)))';


if ~isempty(filter)
    decisions(isnan(dvals)) = nan;
end


% additional output
if nargout >= 3
    nbc = sc;
    if ~isempty(filter)
        nbc = nbc .* is_valid;
    end
end



function [U, inds, m] = unique_map(x)

[inds, U] = slgroups(x);
nu = length(U);
nums = cellfun(@length, inds);
tars = slexpand((1:nu)', nums, 1)';
m = zeros(length(x), 1);
m([inds{:}]) = tars;








